home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-01 / wmv12s.zip / MV.C < prev    next >
Text File  |  1993-01-04  |  10KB  |  359 lines

  1. /* move subdirectories
  2. ** Written by Peter Wu; July 86.
  3. ** compile with cc mv /ze
  4. */
  5. #define LINT_ARGS
  6.  
  7. #define ALLOC 26    /* starting cluster number in directory entry */
  8. #define PLEN 200    /* max path len */
  9.  
  10. #include <dos.h>
  11. #include "dta.h"
  12. #include "peek.h"
  13. #include <conio.h>
  14.  
  15. unsigned char func32h();
  16. unsigned short findir();
  17. unsigned short clus2sec();
  18. char *readsec();
  19. char lastc(char *);
  20.  
  21. /* external var */
  22. extern int
  23.   num_sec,  /* number of sectors buffered */
  24.   brk_st;  /* orginal break status */
  25.  
  26. /* source & dest must be normalized
  27. ** mydta1 contains dta of source
  28. */
  29. mvdir(mydta1,source,dest)  /* move subdirectory */
  30. union dtbuf mydta1;
  31. char *source, *dest;
  32. {
  33.   unsigned short sector1, sector2, offset1, offset2, clus1, clus2,
  34.         d1, d2, status, *p1, *p2, ds1, ds2, bps, parent, drv;
  35.   char *secbuf1, *secbuf2, *secbuf3, cpath[PLEN];
  36.   union dtbuf mydta2;
  37.  
  38.   /* make sure source is not a root directory */
  39.   if (lastc(source) == '\\') {
  40.     cputs("move root directory? You're joking!\n\015");
  41.     exit(1);
  42.   }
  43.  
  44.   /* make sure source is not predesessor of destination */
  45.   if (apreb(source, dest)) {
  46.     /* this will create a directory loop if allowed to go on or
  47.     ** it's a redundant rename to itself (e.g. mv \ha\. \)
  48.     */
  49.     cputs("not moved to avoid loop or redundancy\n\015");
  50.     return -1;
  51.   }
  52.  
  53.   /* see if source is a predesessor of current directory */
  54.   drv = toupper(source[0]) - '@';
  55.   current(drv,cpath);
  56.   if ( apreb(source,cpath) ) {
  57.     cputs("not moved to preserve current directory\n\015");
  58.     return -2;
  59.   }
  60.  
  61.   /* there should be a way to test if source is a predesessor of
  62.   ** a 'subst' drive's current directory
  63.   */
  64.  
  65.   bset(0);  /* do not allow user to break during this portion */
  66.  
  67.   status = mkdir(dest);
  68.   if (status) {
  69.     cputs("can't; file exists already/disk write protected\n\015");
  70.     exit(1);
  71.   }
  72.  
  73.   status = ffmf(dest, A_DIR, &mydta2);
  74.   if (status) {
  75.     cputs("error on ffmf after mkdir\n\015");
  76.     error("mvdir", 0);
  77.   }
  78.  
  79.   num_sec = 0;    /* clear sector buffers */
  80.  
  81.   sector1 = findir(mydta1, &offset1, &d1, &secbuf1);
  82.   if (sector1 < 0) {
  83.     cputs("cannot find source directory\n\015");
  84.     error("mvdir", 0);
  85.   }
  86.  
  87.   sector2 = findir(mydta2, &offset2, &d2, &secbuf2);
  88.   if (sector2 < 0) {
  89.     cputs("cannot get info on destination directory\n\015");
  90.     error("mvdir", 0);
  91.   }
  92.  
  93.   if (d1 != d2) {  /* this should have been detected earlier */
  94.     cputs("source and destination has to be on the same drive\n\015");
  95.     exit(1);
  96.   }
  97.  
  98.   /* now switch the starting cluster of the two directories */
  99.   p1 =    (unsigned short *) (secbuf1 + offset1 + ALLOC);
  100.   p2 =    (unsigned short *) (secbuf2 + offset2 + ALLOC);
  101.   clus1 = *p1;
  102.   clus2 = *p2;
  103. #ifdef debug
  104.   printf("clus1=%4x  clus2=%4x\n", clus1, clus2);
  105. #endif
  106.   *p1 = clus2;
  107.   *p2 = clus1;
  108.  
  109.   status = flirt(d1-1, sector1);  /* mark sector dirty */
  110.   if (status) {
  111.     cputs("error in flirt\n\015");
  112.     error("mvdir", 0);
  113.   }
  114.  
  115.   status = flirt(d1-1, sector2);  /* mark sectors as dirty */
  116.   if (status) {
  117.     cputs("error in flirt\n\015");
  118.     error("mvdir", 0);
  119.   }
  120.  
  121.   /* now we must find the cluster# of the parent directory of the
  122.   ** destination directory (slot number two in clus2) so we can put
  123.   ** it in the source directory (which will become the new destination
  124.   ** directory.
  125.   */
  126.   ds1 = clus2sec(d1, clus1, &bps);  /* sector# of cluster 1 */
  127.   ds2 = clus2sec(d1, clus2, &bps);  /* sector# of cluster 2 */
  128.   secbuf3 = readsec(d1-1,ds2);
  129.   if (secbuf3 == (char *) 0) {
  130.     cputs("error in calling readsec\n\015");
  131.     error("mvdir", 0);
  132.   }
  133.  
  134.   parent = * (unsigned short *) (secbuf3 + 32 + ALLOC);
  135. #ifdef debug
  136.   printf("parent is %4x\n", parent );
  137. #endif
  138.  
  139.   /* now write this into source dir */
  140.  
  141.   secbuf3 = readsec(d1-1,ds1);
  142.   if (secbuf3 == (char *) 0) {
  143.     cputs("error in calling readsec\n\015");
  144.     error("mvdir", 0);
  145.   }
  146.  
  147.   *(unsigned short *) (secbuf3 + 32 + ALLOC) = parent;
  148.   status = flirt(d1-1,ds1);
  149.   if (status) {
  150.     cputs("error in flirt\n\015");
  151.     error("mvdir", 0);
  152.   }
  153.  
  154.   /* now write back all three (or less) modified sectors */
  155.   status = writesec(d1-1,ds1);    /* the cluster containing parent pointer */
  156.   if (status) {  /* what could cause this to happen? */
  157.     cputs("error in writing first modified sector\n\015");
  158.     error("mvdir", 1);
  159.   }
  160.  
  161.   status = writesec(d1-1,sector2);
  162.   if (status) {  /* it's impossible for this to happen */
  163.     cputs("error in writing second modified sector\n\015");
  164.     error("mvdir", 1);
  165.   }
  166.  
  167.   status = writesec(d1-1,sector1);
  168.   if (status) {  /* this is also impossible */
  169.     cputs("error in writing third modified sector\n\015");
  170.     error("mvdir", 1);
  171.   }
  172.  
  173.   bdos(0xd,0,0);  /* reset disk - neccessary for rmdir to work since DOS'
  174.           ** buffer now contains invalid information (it didn't
  175.           ** know that the disk was modified).
  176.           */
  177.   status = rmdir(source);  /* this dir should be empty now */
  178.   if (status) {
  179.     putn(
  180. "Oops!\n\015",
  181. "cannot remove old directory \"", source, "\"\n\015",
  182. "Maybe one of your `subst' disk is using this directory. If this is\n\015",
  183. "the case, remove the subst disk and then remove this directory.\n\015", 0);
  184.     exit(1);
  185.   }
  186.  
  187.   bset(brk_st);  /* restore break status */
  188.   return 0;  /* no error */
  189. }
  190.  
  191. unsigned short findir(mydta, offsetp, drv, secbuf)
  192. char **secbuf;
  193. unsigned short *offsetp;
  194. unsigned int *drv;
  195. union dtbuf mydta;
  196. {
  197.   unsigned int status, i, j, offset, sector, cluster, tmp, bps;
  198.   union REGS inregs, outregs;
  199.   struct SREGS segregs;
  200.   char c, dir[13];  /* directory entry formatted like X.Y not "X       Y  " */
  201.  
  202.   if (mydta.dos.attr != A_DIR) {  /* guard against programmer's error */
  203.     putn(mydta.dos.fn, " is not a directory\n\015",0);
  204.     error("findir", 0);
  205.   }
  206.  
  207.   /* now find the cluster where the searched directory is */
  208.   cluster = mydta.dos.clusl + (mydta.dos.clush << 8);
  209.  
  210.   /* now convert the cluster number to sector number */
  211.   sector = clus2sec(mydta.dos.drv_no, cluster, &bps);
  212.  
  213.   /* calculate directory entry offset in the sector */
  214.   offset = ((mydta.dos.sloth << 8) + mydta.dos.slotl) * 32;
  215.  
  216.   sector += offset / bps;  /* normalize sector & offset */
  217.   offset %= bps;
  218.  
  219. #ifdef debug
  220.   printf("dir at sector %d\n", sector);
  221. #endif
  222.  
  223.   *secbuf = readsec(mydta.dos.drv_no - 1, sector);
  224.   if (*secbuf == (char *) 0) {
  225.     cputs("error in calling readsec\n\015");
  226.     error("findir", 0);
  227.   }
  228.  
  229. #ifdef debug
  230.   printf("First 11 bytes in sector: %11.11s\n", *secbuf+offset);
  231.   printf("Fn returned by ffmf: %11.11s\n", mydta.fn);
  232. #endif
  233.  
  234.   /* redundant check to see if we have the correct directory entry */
  235.   /* first format the directory entry name in this form "*.*" instead of
  236.   ** "???????????"
  237.   */
  238.   i=0;
  239.   c = (*secbuf)[offset];
  240.   while ((c != ' ') && (i < 8)) {  /* copy the first 8 characters */
  241.     dir[i] = c;
  242.     i++;
  243.     c = (*secbuf)[offset+i];
  244.   }
  245.  
  246.   j = 8;
  247.   c = (*secbuf)[offset+j];
  248.   if (c != ' ') {  /* sub-dir name has extension */
  249.     /* now add '.' and copy the extension */
  250.     dir[i] = '.';
  251.     i++;
  252.     while ((c != ' ') && (j < 11)) {
  253.       dir[i] = c;
  254.       i++;
  255.       j++;
  256.       c = (*secbuf)[offset + j];
  257.     }
  258.   }
  259.   dir[i] = '\0';  /* terminate string */
  260. #ifdef debug
  261.   printf("formatted directory entry string: %s\n", dir);
  262. #endif
  263.  
  264.   if (strcmp(mydta.dos.fn, dir) == 0) {
  265. #ifdef debug
  266.     printf("Directory entry found!\n");
  267. #endif
  268.   } else {
  269.     cputs("cannot find directory entry\n\015");
  270.     error("findir", 0);
  271.   }
  272.  
  273.   /* redundant check to make sure file size of directory is zero */
  274.   if (*(unsigned long *)(*secbuf+offset+28) != 0L) {
  275.     cputs("found directory with size > 0\n\015");
  276.     error("findir", 0);
  277.   }
  278.  
  279.   *offsetp = offset;
  280.   *drv = mydta.dos.drv_no;
  281.   return sector;
  282. }
  283.  
  284. unsigned short clus2sec(drv, clus_no, pbps)  /* convert cluster to sector */
  285. unsigned short clus_no, *pbps, drv;
  286. {
  287.   unsigned char status;
  288.   static unsigned short spc=0, ss, bps, tabseg, taboff;
  289.   unsigned short sector;
  290.  
  291.   if (spc == 0) {  /* first time function is called */
  292.     status = func32h(drv, &tabseg, &taboff);  /* See PC Tech Journal */
  293.     if (status == 0xff) {
  294.       cputs("func32h: invalid drive: "); putch(drv+'A'); cputs("\n\015");
  295.       error("clus2sec", 0);
  296.     }
  297.  
  298.     spc = peekb(tabseg,taboff+4)+1;  /* sector per cluster */
  299.     ss =  peekw(tabseg,taboff+11);  /* starting data sector */
  300.     bps = peekw(tabseg,taboff+2);  /* bytes per sector */
  301.  
  302. #ifdef debug
  303.     printf("drive #: %d\n", drv);
  304.     printf("sectors per cluster: %d\n", spc);
  305.     printf("# allocation units: %d\n",  peekw(tabseg,taboff+13)-1 );
  306.     printf("sector size: %d\n", bps);
  307.     printf("starting sector: %d\n", ss);
  308. #endif
  309.   }
  310.   *pbps = bps;    /* return this value */
  311.  
  312.   if (clus_no == 0) {
  313. #ifdef debug
  314.     printf("parent directory is root! - special case\n");
  315. #endif
  316.     sector = peekw(tabseg,taboff+16);  /* first sector of root directory */
  317.   } else {
  318.     sector = (clus_no - 2) * spc + ss;    /* see DOS Tech. Ref */
  319.   }
  320.  
  321.   return sector;
  322. }
  323.  
  324. /* apreb test to see if patha is equal to or is a predessesor of pathb
  325. ** This is used to test whether moving a directory would result
  326. ** in a directory loop condition and also whether the source
  327. ** directory is a predessor of the current path (can't delete
  328. ** source directory in this case, so don't move)
  329. **
  330. ** patha and pathb must be normalized paths
  331. ** E.g.
  332. **       apreb("A:\DEF", "A:\DEF")    is true
  333. **       apreb("A:\DEF", "A:\DEF\GHI")   is also true
  334. **       apreb("A:\DEF", "A:\DEFG")    is false
  335. */
  336. apreb(patha, pathb)
  337. char *patha, *pathb;
  338. {
  339.   int i, lena, lenb;
  340.   char c;
  341.  
  342.   lena = strlen(patha);
  343.   lenb = strlen(pathb);
  344.   if (lena > lenb) {  /* if patha is longer, it can't be a predessesor */
  345.     return 0;
  346.   }
  347.  
  348.   c = pathb[lena];  /* if patha is a predessesor, c should be '\\' or '\0' */
  349.   if ((c != '\\') && (c != '\0')) {
  350.     return 0;
  351.   }
  352.  
  353.   if (strncmp(patha, pathb, lena)) {  /* not equal */
  354.     return 0;
  355.   }
  356.  
  357.   return 1;
  358. }
  359.